package net.gdface.sdk;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;

import net.gdface.utils.Judge;
import static net.gdface.utils.SimpleLog.log;
import static net.gdface.sdk.CapacityFieldConstant.C_SDK_VERSION;

/**
 * FaceApi应用上下文SPI加载工具类
 * @author guyadong
 *
 */
public class ContextLoader {
	private static final Map<GlobalContextField, Object> globalContext = new HashMap<>();
	private static final ThreadLocal<Map<GlobalContextField, Object>> localContext = new ThreadLocal<Map<GlobalContextField, Object>>(){

		@Override
		protected Map<GlobalContextField, Object> initialValue() {
			return new HashMap<>();
		}
		
	};
	private final LinkedHashMap<String, FaceApiContext> classMap = new LinkedHashMap<>();
	private final LinkedHashMap<String, FaceApiContext> versionMap= new LinkedHashMap<>();
	/** 所有找到的 FaceApi 上下文实例 */
	public final List<FaceApiContext> CONTEXTS ;
	// 延迟加载的单实例
	private static class Singleton{
		static final ContextLoader INSTANCE = new ContextLoader();
	}
	/**
	 * 全局上下文字段定义
	 */
	public static enum GlobalContextField{
		/** 并发限制 [int]*/CONCURRENCY,
		/** 人脸检测倾向, [boolean] true:多人脸检测,false:用于帧相关单人脸检测 */MULIT_FACE_DETECT_TREND
	}
	/**
	 * 上下文字段定义
	 */
	public static enum ContextField{
		/** {@link FaceApi}实例 */INSTANCE,
		/** 授权管理器(LicenceManager)实例 */LICENCE_MANAGER;
		@SuppressWarnings("unchecked")
		public <T>T from(FaceApiContext context){
			return (T) context.getContext().get(this);
		}
	}
	public  static final ContextLoader getInstance(){
		return Singleton.INSTANCE;
	}
	private ContextLoader() {
		// SPI 加载所有 FaceApi 上下文实例
		ServiceLoader<FaceApiContext> providers = ServiceLoader.load(FaceApiContext.class);
		LinkedList<FaceApiContext> list = new LinkedList<>();
		for(Iterator<FaceApiContext> itor = providers.iterator();itor.hasNext();){
			FaceApiContext context = itor.next();
			list.add(context);
			FaceApi instance = ContextLoader.ContextField.INSTANCE.<FaceApi>from(context);
			if(instance == null){
				// 跳过接口实例为空的并报错
				log("ERROR:FaceApi instance of {} is null",context.getClass().getName());
				continue;
			}
			classMap.put(instance.getClass().getName(), context);
			String sdkVersion = instance.sdkCapacity().get(C_SDK_VERSION);
			if(!Judge.isEmpty(sdkVersion)){
				versionMap.put(sdkVersion, context);
			}
		}
		CONTEXTS =  Collections.unmodifiableList(list);
	}
	/**
	 * 返回找到的第一个FaceApi应用上下文实例
	 * @return FaceApi应用上下文实例,找不到返回{@code null}
	 */
	public FaceApiContext getContext(){
		try {
			return CONTEXTS.get(0);
		} catch (IndexOutOfBoundsException e) {
			return null;
		}
	}
	/**
	 * 返回找到的第一个FaceApi应用上下文实例
	 * @return FaceApi应用上下文实例
	 * @throws IllegalStateException 找不到FaceApi应用上下文实例
	 */
	public FaceApiContext getContextChecked(){
		try {
			return CONTEXTS.get(0);
		} catch (IndexOutOfBoundsException e) {
			throw new IllegalStateException("NOT FOUND any " + FaceApiContext.class.getSimpleName() + " instance");
		}
	}
	/**
	 * 返回包含指定FaceApi实例类名的应用上下文
	 * @param className FaceApi实例类名(全名)
	 * @return FaceApi应用上下文实例,找不到返回{@code null}
	 */
	public FaceApiContext getContextByInstnaceClass(String className){
		return classMap.get(className);
	}
	/**
	 * 返回包含指定FaceApi实例类名的应用上下文
	 * @param className FaceApi实例类名(全名)
	 * @return FaceApi应用上下文实例
	 * @throws IllegalArgumentException 找不到指定的上下文实例
	 */
	public FaceApiContext getContextByInstnaceClassChecked(String className){
		FaceApiContext context = classMap.get(className);
		if(context == null){
			throw new IllegalArgumentException("INVALID instance class name: " + className);
		}
		return context;
	}
	/**
	 * 返回支持指定SDK版本号的应用上下文
	 * @param sdkVersion SDK版本号
	 * @return FaceApi应用上下文实例,找不到返回{@code null}
	 */
	public FaceApiContext getContextBySdkVersion(String sdkVersion){
		return versionMap.get(sdkVersion);
	}
	/**
	 * 返回支持指定SDK版本号的应用上下文
	 * @param sdkVersion SDK版本号
	 * @throws IllegalArgumentException 找不到指定的上下文实例
	 */
	public FaceApiContext getContextBySdkVersionChecked(String sdkVersion){
		FaceApiContext context = versionMap.get(sdkVersion);
		if(context == null){
			throw new IllegalArgumentException("INVALID sdkVersion: " + sdkVersion);
		}
		return context;
	}
	/**
	 * 设置全局上下文,用于应用层在SDK初始化前指定初始化参数<br>
	 * @param field
	 * @param value
	 */
	public static void setGlobalContext(GlobalContextField field,Object value){
		if(field != null && value != null){
			globalContext.put(field, value);
		}
	}
	@SuppressWarnings("unchecked")
	public static <T>T getGlobalContext(GlobalContextField field) {
		if(field != null ){
			return (T) globalContext.get(field);
		}
		return null;
	}
	/**
	 * 设置当前线程上下文,用于应用层在SDK初始化前指定初始化参数<br>
	 * @param field
	 * @param value
	 */
	public static void setLocalContext(GlobalContextField field,Object value){
		if(field != null && value != null){
			localContext.get().put(field, value);
		}
	}
	@SuppressWarnings("unchecked")
	public static <T>T getLocalContext(GlobalContextField field) {
		if(field != null ){
			return (T) localContext.get().get(field);
		}
		return null;
	}
	/**
	 * 返回{@code field}上下文参数<br>
	 * 优先返回当前线程保存的上下文参数,如果返回{@code null},则返回全局上下文参数
	 * @param field
	 * @return value for {@code field}
	 */
	public static <T>T getContext(GlobalContextField field) {
		T value = getLocalContext(field);
		if(null == value){
			value = getGlobalContext(field);
		}
		return value;
	}
	/**
	 * 返回{@code field}上下文参数<br>
	 * 优先返回当前线程保存的上下文参数,如果返回{@code null},则返回全局上下文参数,返回{@code null}则返回默认值{@code defaultValue}
	 * @param field
	 * @param defaultValue 默认值
	 * @return value for {@code field}
	 */
	public static <T>T getContext(GlobalContextField field,T defaultValue) {
		T value = getLocalContext(field);
		if(null == value){
			value = getGlobalContext(field);
		}
		return null == value ? defaultValue : value;
	}
}
